﻿using System;
using System.ComponentModel;

namespace Notoric.ViewModel.Elements.CWNotation
{
    /// <summary>
    /// Represents one flag.
    /// </summary>
    public class Flag : VirtualViewModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="Flag"/> instance.
        /// </summary>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="Chord"/>
        /// </para>
        /// <para>
        /// The chord that directly owns this flag.
        /// </para>
        /// </param>
        /// <param name="order">
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The order of the flag (1st flag has order 0).
        /// </para>
        /// </param>
        /// <param name="last">
        /// <para>
        /// Type: <see cref="Boolean"/>
        /// </para>
        /// <para>
        /// Indicates whether this flag is the last one.
        /// </para>
        /// </param>
        internal Flag(Chord owner, int order, bool last)
            : base(owner)
        {
            this.order = order;
            this.isLast = last;

            RegisterToOwnerPropertyChanged<Chord>();
        }

        #endregion

        #region VirtualViewModelElement Members

        /// <inheritdoc/>
        public override void Dispose()
        {
            UnregisterFromOwnerPropertyChanged<Chord>();
            base.Dispose();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the value of some owner's property has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// If the modified property is <see cref="CoreSymbol.Position"/>, the handler raises the <see cref="VirtualViewModelElement.PropertyChanged"/>
        /// event for the <see cref="Position"/> property.<br/>
        /// If the modified property is <see cref="Chord.StemEnd"/>, the handler raises the <see cref="VirtualViewModelElement.PropertyChanged"/>
        /// event for the <see cref="VerticalPosition"/> property.<br/>
        /// If the modified property is <see cref="Chord.StemDirection"/>, the handler raises the <see cref="VirtualViewModelElement.PropertyChanged"/>
        /// event for the <see cref="Orientation"/> property.
        /// </remarks>
        /// <param name="owner">The owner that has sent the event</param>
        /// <param name="e">Event data</param>
        protected override void Owner_PropertyChanged(ViewModelElement owner, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Position")
                RaisePropertyChanged("Position");
            else if (e.PropertyName == "StemEnd")
                RaisePropertyChanged("VerticalPosition");
            else if (e.PropertyName == "StemDirection")
                RaisePropertyChanged("Orientation");
        }
        
        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the value indicating whether this flag is the last one.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Boolean"/>
        /// </para>
        /// <para>
        /// Indicates whether this flag is the last one (bottom most if stem is oriented <see cref="StemOrientation.Down"/>,
        /// topmost otherwise).
        /// </para>
        /// </value>
        public bool IsLast
        {
            get { return isLast; }
            set
            {
                isLast = value;
                RaisePropertyChanged("IsLast");
            }
        }

        /// <summary>
        /// Gets the order of the flag.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The order of the flag. First flag has order 0.
        /// </para>
        /// </value>
        public int Order
        {
            get { return order; }
        }

        /// <summary>
        /// Gets the orientation of the flag.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="StemOrientation"/>
        /// </para>
        /// <para>
        /// The orientation of the flag.
        /// </para>
        /// </value>
        public StemOrientation Orientation
        {
            get { return FindOwner<Chord>().StemDirection; }
        }

        /// <summary>
        /// Gets the horizontal position of the flag.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The horizontal position (in device independent pixels) of the flag.
        /// </para>
        /// </value>
        public double Position
        {
            get { return FindOwner<Chord>().Position; }
        }

        /// <summary>
        /// Gets the vertical position of the flag.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The vertical positon (in device independent pixels) of the flag.
        /// </para>
        /// </value>
        public double VerticalPosition
        {
            get 
            {
                var myChord = FindOwner<Chord>();

                var staffSpaces = FindOwner<ViewModel.Elements.CWNotation.Staff>().Lines.Count - 1;
                var spaceSize = (staffSpaces > 0 ? myChord.EffectiveTypeSize / staffSpaces : FindOwner<ViewModel.Elements.CWNotation.Staff>().SpaceSize);
                var step = (myChord.StemDirection == StemOrientation.Up ? 0.7 * spaceSize : -0.7 * spaceSize);

                return myChord.StemEnd + order * step;
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the value of the <see cref="IsLast"/> property.
        /// </summary>
        private bool isLast;
        /// <summary>
        /// Holds the value of the <see cref="Order"/> property.
        /// </summary>
        private int order;

        #endregion
    }
}
